package com.sky.es.service.impl;

import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.sky.es.entity.ProductDoc;
import com.sky.es.service.ProductAggsQueryEsService;
import lombok.extern.slf4j.Slf4j;
import org.elasticsearch.search.aggregations.Aggregation;
import org.elasticsearch.search.aggregations.AggregationBuilders;
import org.elasticsearch.search.aggregations.Aggregations;
import org.elasticsearch.search.aggregations.bucket.terms.ParsedStringTerms;
import org.elasticsearch.search.aggregations.bucket.terms.Terms;
import org.elasticsearch.search.aggregations.bucket.terms.TermsAggregationBuilder;
import org.elasticsearch.search.aggregations.metrics.ParsedCardinality;
import org.elasticsearch.search.aggregations.metrics.ParsedStats;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.elasticsearch.core.ElasticsearchRestTemplate;
import org.springframework.data.elasticsearch.core.SearchHits;
import org.springframework.data.elasticsearch.core.query.NativeSearchQuery;
import org.springframework.data.elasticsearch.core.query.NativeSearchQueryBuilder;
import org.springframework.stereotype.Service;

import java.util.List;
import java.util.Optional;

/**
 * @author yangsk
 */
@Service
@Slf4j
public class ProductAggsQueryEsServiceImpl implements ProductAggsQueryEsService {
    @Autowired
    private ElasticsearchRestTemplate esRestTemplate;

    @Override
    public JSONArray getQueryAggsBucket() {
        NativeSearchQuery aggsBucketQuery = new NativeSearchQueryBuilder()
                .addAggregation(AggregationBuilders.terms("lv_bucket").field("lv.keyword")).build();
        SearchHits<ProductDoc> aggsResult = esRestTemplate.search(aggsBucketQuery, ProductDoc.class);
        JSONArray array = new JSONArray();
        if(null != aggsResult){
            Aggregations aggregations = (Aggregations)aggsResult.getAggregations().aggregations();
            Aggregation lvBucket = aggregations.get("lv_bucket");
            List<? extends Terms.Bucket> buckets = ((ParsedStringTerms) lvBucket).getBuckets();
            buckets.forEach(bucket -> {
                JSONObject json = new JSONObject();
                json.put("doc_key", Optional.ofNullable(bucket.getKeyAsString()).orElse("empty"));
                json.put("doc_count", Optional.ofNullable(bucket.getDocCount()).orElse(0l));
                array.add(json);
            });
           return array;
        }
        return null;
    }

    @Override
    public void getQueryAggsMatric() {

        NativeSearchQuery distinctQuery = new NativeSearchQueryBuilder()
                .addAggregation(AggregationBuilders.cardinality("distinct_type").field("type.keyword")).build();
        SearchHits<ProductDoc> aggsResult = esRestTemplate.search(distinctQuery, ProductDoc.class);
        if(null != aggsResult){
            Aggregations aggregations = (Aggregations)aggsResult.getAggregations().aggregations();
            ParsedCardinality distinctType = (ParsedCardinality)aggregations.asMap().get("distinct_type");
            long value = distinctType.getValue();
            log.info("matric:===={}",value);
        }
    }

    @Override
    public JSONObject getQueryAggsMatricStats() {
        NativeSearchQuery matricQuery = new NativeSearchQueryBuilder()
                .addAggregation(AggregationBuilders.stats("matric_stats").field("price")).build();
        SearchHits<ProductDoc> aggsResult = esRestTemplate.search(matricQuery, ProductDoc.class);
        JSONObject jsonResult = new JSONObject();
        if(null != aggsResult){
            Aggregations aggregations = (Aggregations)aggsResult.getAggregations().aggregations();
            ParsedStats matricStats = (ParsedStats)aggregations.asMap().get("matric_stats");
            jsonResult.put("max",Optional.ofNullable(matricStats.getMax()).orElse(0.0));
            jsonResult.put("min",Optional.ofNullable(matricStats.getMin()).orElse(0.0));
            jsonResult.put("avg",Optional.ofNullable(matricStats.getAvg()).orElse(0.0));
            jsonResult.put("sum",Optional.ofNullable(matricStats.getSum()).orElse(0.0));
            jsonResult.put("count",Optional.ofNullable(matricStats.getCount()).orElse(0l));
            log.info("matricStats:===={}",matricStats);
            return jsonResult;
        }
        return null;
    }

    @Override
    public JSONArray getQueryByNestAggs() {

        //ValueCountAggregationBuilder queryCondition = AggregationBuilders.count("sugg_type_count").field("type.keyword");
        TermsAggregationBuilder suggTypeCount = AggregationBuilders
                .terms("sugg_type_count")
                .field("type.keyword")
                .subAggregation(AggregationBuilders
                        .terms("sugg_lv_count")
                        .field("lv.keyword")
                );
        NativeSearchQuery queryResult = new NativeSearchQueryBuilder()
                .withAggregations(suggTypeCount)
                .build();
        SearchHits<ProductDoc> aggsResult = esRestTemplate.search(queryResult, ProductDoc.class);
        Aggregations aggregations = (Aggregations)aggsResult.getAggregations().aggregations();
        Aggregation typeGroupResult = aggregations.get("sugg_type_group");
        List<? extends Terms.Bucket> typeCountBuckets = ((ParsedStringTerms) typeGroupResult).getBuckets();
        JSONArray jsonArray = new JSONArray();
        for(Terms.Bucket bucket:typeCountBuckets){
            Aggregation suggLvCount = bucket.getAggregations().get("sugg_type_group");
            List<? extends Terms.Bucket> lvCountBuckets = ((ParsedStringTerms) suggLvCount).getBuckets();
            JSONObject jsonObject = new JSONObject();
            jsonObject.put("docCount",Optional.ofNullable(bucket.getDocCount()).orElse(0l));
            jsonObject.put("key",Optional.ofNullable(bucket.getKeyAsString()).orElse(null));
            JSONArray lvCountArray = new JSONArray();
            for(Terms.Bucket countBucket:lvCountBuckets){
                JSONObject lvJsonObject =   new JSONObject();
                lvJsonObject.put("docCount",Optional.ofNullable(countBucket.getDocCount()).orElse(0l));
                lvJsonObject.put("key",Optional.ofNullable(countBucket.getKeyAsString()).orElse(null));
                lvCountArray.add(lvJsonObject);
                jsonObject.put("buckets",lvCountArray);
            }
            jsonArray.add(jsonObject);
        }
        return jsonArray;
    }

    @Override
    public JSONArray getQueryTwoByNestAggs() {
        TermsAggregationBuilder suggLvGroup = AggregationBuilders
                .terms("sugg_lv_group").field("lv.keyword")
                .subAggregation(AggregationBuilders.stats("price_stats").field("price"));
        NativeSearchQuery queryResult = new NativeSearchQueryBuilder()
                .withAggregations(suggLvGroup)
                .build();

        SearchHits<ProductDoc> aggsResult = esRestTemplate.search(queryResult, ProductDoc.class);
        Aggregations aggregations = (Aggregations)aggsResult.getAggregations().aggregations();
        Aggregation typeGroupResult = aggregations.get("sugg_lv_group");
        List<? extends Terms.Bucket> lvGroupBuckets = ((ParsedStringTerms) typeGroupResult).getBuckets();
        JSONArray jsonArray = new JSONArray();
        for(Terms.Bucket bucket:lvGroupBuckets){
            JSONObject jsonObject =   new JSONObject();
            jsonObject.put("docCount",Optional.ofNullable(bucket.getDocCount()).orElse(0l));
            jsonObject.put("key",Optional.ofNullable(bucket.getKeyAsString()).orElse(null));

            ParsedStats suggPriceStats = (ParsedStats)bucket.getAggregations().get("price_stats");
            JSONObject priceStats = new JSONObject();
            priceStats.put("count",Optional.ofNullable(suggPriceStats.getCount()).orElse(0l));
            priceStats.put("max",Optional.ofNullable(suggPriceStats.getMax()).orElse(0.0));
            priceStats.put("min",Optional.ofNullable(suggPriceStats.getMin()).orElse(0.0));
            priceStats.put("avg",Optional.ofNullable(suggPriceStats.getAvg()).orElse(0.0));
            priceStats.put("sum",Optional.ofNullable(suggPriceStats.getSum()).orElse(0.0));
            jsonObject.put("priceStats",priceStats);
            jsonArray.add(jsonObject);
        }
        return jsonArray;
    }
}
